/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "面/面.h"
#include "物体/物体.h"
#include "core/空间划分/球形八叉树.h"
#include "core/几何计算/碰撞.h"

#include <matXX.h>
#include <三角形.h>
#include "网格顶点组编辑.h"




static void f_收集骨骼封套(std::vector<S_封套>& 封套, S_物体* 骨骼) {
	if (骨骼->m_Type == E_物体类型::t_骨骼) {
		封套.push_back(f_ob_get骨骼封套(f_ob_from骨骼(骨骼)));

		uint32 num = 骨骼->m_子物体.size();
		for (uint32 i = 0; i < num; ++i) {
			f_收集骨骼封套(封套, static_cast<S_物体*>(骨骼->m_子物体[i]));
		}
	}
}


static void f_计算邻接骨骼属性(uint32 骨节数量, S_BonePose* 骨骼姿态, std::vector<S_骨骼属性>& 邻接骨骼属性) {
	//uint32 骨节数量 = 骨架->m_骨节数量;

	邻接骨骼属性.resize(骨节数量);
	for (uint32 k = 0; k < 骨节数量; ++k) {
		S_骨骼属性 骨骼属性{}; 

		float32 boneLen = 骨骼姿态[k].tranformBoneA.w;

		vec3 dir = 骨骼姿态[k].dir;
		vec3 bs = _Vec3(骨骼姿态[k].tranformBoneA);
		骨骼属性.变换后中点 = bs + dir * (boneLen * 0.5);
		
		骨骼属性.A端平面 = f_graph_坐标构建平面(bs, dir);
		骨骼属性.B端平面 = f_graph_坐标构建平面(bs + dir * boneLen, dir);
		骨骼属性.骨骼中间平面 = f_graph_坐标构建平面(骨骼属性.变换后中点, dir);
		
		骨骼属性.骨骼方向 = 骨骼姿态[k].dir;
		骨骼属性.骨骼长度 = boneLen;

		邻接骨骼属性[k] = 骨骼属性;
	}
}

void f_surface_计算自动权重(S_Mesh* me, const Mat44f& mat, S_骨架* 骨架, float32 封套范围比例) {
	uint32 num = me->f_get顶点数量();
	
	std::vector<S_BoneMap>	骨骼映射;
	std::vector<S_VertBone>	顶点骨骼(num);

	//uint32 权重层数 = 4;
	uint32 骨头数量 = 骨架->m_骨头数量;
	if (骨头数量) {
		S_BonePose* 骨骼姿态 = f_buf_骨骼姿态_ptr(骨架->m_姿态);

		std::vector<vec3> 变换后顶点(num);
		vec3* vert_p = 变换后顶点.data();
		std::vector<vec3> 变换后法线(num);
		vec3* normal_p = 变换后法线.data();


		vec3 bounding = f_surface_get包围盒大小(me, mat);
		auto* tree = f_空间划分_create球形八叉树(DEF_Max(DEF_Max(bounding.x, bounding.y), bounding.z));


		uint32 骨节数量 = 骨架->m_骨节数量;



		auto* 邻接骨骼ID = 骨架->m_骨骼邻接->ptr_userData;

		std::vector<S_骨骼属性> 邻接骨骼属性;
		f_计算邻接骨骼属性(骨节数量, 骨骼姿态, 邻接骨骼属性);
		

		std::vector<std::vector<uint16>> 顶点所属骨骼(num);
		for (uint32 i = 0; i < num; ++i) {
			
			//vec3 vert;
			switch (*me->m_顶点配置Flags) {
				case E_顶点组合标志::e_坐标_法线_UV: {
					vert_p[i] = mat * f_buf_VNT_ptr(*me->m_顶点)[i].vert;
					break;
				}
				default:
					break;
			}

			
			for (uint32 k = 0; k < 骨节数量; ++k) {
				S_骨骼属性& 骨骼属性 = 邻接骨骼属性[k];

				vec3 bs = _Vec3(骨骼姿态[k].tranformBoneA);
				
				//float32 d = vec_len(vert_p[i] - 变换后中点[k]);
				float32 Ad = f_graph_点到平面距离(vert_p[i], 骨骼属性.A端平面);
				float32 Bd = f_graph_点到平面距离(vert_p[i], 骨骼属性.B端平面);
				if (骨骼属性.骨骼长度 > 0) {
					float32 d = f_graph_点到直线距离(bs, 骨骼属性.骨骼方向, vert_p[i]);

					if (d < 骨骼属性.骨骼长度*2 && Ad >= 0 && Bd < 0) {
						顶点所属骨骼[i].push_back(k);
					}
				}
			}
		}


		for (uint32 i = 0; i < num; ++i) {
			vec3 vert = vert_p[i];
			vec3 normal;
			switch (*me->m_顶点配置Flags) {
				case E_顶点组合标志::e_坐标:
					break;
				case E_顶点组合标志::e_坐标_法线:
					break;
				case E_顶点组合标志::e_坐标_法线_UV: {
					normal = mat * f_buf_VNT_ptr(*me->m_顶点)[i].normal;
					break;
				}
				case E_顶点组合标志::e_坐标_颜色:
					break;
				case E_顶点组合标志::e_坐标_UV:
					break;
				default:
					break;
			}



			std::vector<S_BoneMap>	顶点骨骼权重;
			for (auto 顶点所属骨骼ID : 顶点所属骨骼[i]) {
				uint32 k = 顶点所属骨骼ID;
				
				S_骨骼属性& 骨骼属性 = 邻接骨骼属性[k];

				float32 boneLen = 骨骼姿态[k].tranformBoneA.w;
				float32 封套大小 = 骨骼姿态[k].tranformBoneB.w;
				
				
				if (boneLen <= 0) {
					continue;
				}
				float32 骨头一半长度 = boneLen * 0.5f;

				vec3 dir = 骨骼属性.骨骼方向;
				vec3 bs = _Vec3(骨骼姿态[k].tranformBoneA);
				vec3 es = bs + dir * boneLen;
				
				//float32 d = f_graph_点到直线距离(bs, dir, vert_p[i]);
				vec4 骨骼中间平面 = f_graph_坐标构建平面(骨骼属性.变换后中点, 骨骼属性.骨骼方向);
				float32 d = f_graph_点到直线距离(bs, 骨骼属性.骨骼方向, vert);
				float32 pd = f_graph_点到平面距离(vert, 骨骼中间平面);
				
				

				if (d > 骨头一半长度) {
					//顶点到骨骼距离 = DEF_Min(顶点到骨骼距离, boneLen * 1.5);
					
					//float32 顶点到骨骼距离 = DEF_Min(d - 骨头一半长度, 骨头一半长度 * 2);
					//
					//float32 权重 = f_bone_外围权重计算(vert, 顶点所属骨骼[i], 邻接骨骼属性.data(), 骨头一半长度, 顶点到骨骼距离, k, 骨架->m_骨骼邻接, pd);
					//if (权重 > 0) 顶点骨骼权重.push_back({ k, 权重 });
					//
					//
					//pd = f_graph_点到平面距离(vert, 邻接骨骼属性[k].A端平面);
					//for (uint32 j = 0; j < 邻接骨骼ID[k]->m_子骨骼->count; ++j) {
					//	uint32 当前邻接骨骼ID = 邻接骨骼ID[k]->m_子骨骼->ptr_userData[j];
					//	顶点到骨骼距离 = DEF_Min(d - 骨头一半长度, boneLen);
					//
					//	权重 = f_bone_外围邻接权重计算(vert, pd, boneLen, 顶点到骨骼距离);
					//	if (权重 > 0) 顶点骨骼权重.push_back({ 当前邻接骨骼ID, 权重 });
					//}
					//
					//
					//
					//int32 当前邻接骨骼ID = 邻接骨骼ID[k]->m_父骨骼ID;
					//if (当前邻接骨骼ID > 0) {
					//	顶点到骨骼距离 = DEF_Min(d - 骨头一半长度, boneLen);
					//
					//	pd = f_graph_点到平面距离(vert, 邻接骨骼属性[k].B端平面);
					//	权重 = f_bone_外围邻接权重计算(vert, pd, boneLen, 顶点到骨骼距离);
					//	if (权重 > 0) 顶点骨骼权重.push_back({ uint32(当前邻接骨骼ID), 权重 });
					//}
						
					
				}
				else {
					
					float32 顶点到骨骼距离 = DEF_Min(d, 骨头一半长度);

					if (pd >= 0) {
						float32 权重 = f_bone_B端权重计算(es, dir, vert, 顶点所属骨骼[i], 邻接骨骼属性.data(), 顶点到骨骼距离, k, 骨架->m_骨骼邻接);
						if (权重 > 0) 顶点骨骼权重.push_back({ k, 权重 });


						for (uint32 j = 0; j < 邻接骨骼ID[k]->m_子骨骼->count; ++j) {
							uint32 当前邻接骨骼ID = 邻接骨骼ID[k]->m_子骨骼->ptr_userData[j];
							
							//dir = 骨骼姿态[当前邻接骨骼ID].dir;
							//bs = _Vec3(骨骼姿态[当前邻接骨骼ID].tranformBoneA);
							//es = bs + dir * 骨骼姿态[当前邻接骨骼ID].tranformBoneA.w;

							顶点到骨骼距离 = DEF_Min(d, 骨骼姿态[当前邻接骨骼ID].tranformBoneA.w);
							权重 = f_bone_B端邻接权重计算(vert, 邻接骨骼属性.data(), 顶点到骨骼距离, 当前邻接骨骼ID);
							if (权重 > 0) 顶点骨骼权重.push_back({ 当前邻接骨骼ID, 权重 });
							
						}
						//pd = 0;
					}
					else {
						float32 权重 = f_bone_A端权重计算(bs, dir, vert, 顶点所属骨骼[i], 邻接骨骼属性.data(), 顶点到骨骼距离, k, 骨架->m_骨骼邻接);
						if (权重 > 0) 顶点骨骼权重.push_back({ k, 权重 });


						int32 当前邻接骨骼ID = 邻接骨骼ID[k]->m_父骨骼ID;
						if (当前邻接骨骼ID >= 0) {
							//dir = 骨骼属性.骨骼方向;
							//dir = 骨骼姿态[当前邻接骨骼ID].dir;
							//bs = _Vec3(骨骼姿态[当前邻接骨骼ID].tranformBoneA);
							//es = bs + dir * 骨骼姿态[当前邻接骨骼ID].tranformBoneA.w;

							顶点到骨骼距离 = DEF_Min(d, 骨骼姿态[当前邻接骨骼ID].tranformBoneA.w);
							//权重 = f_bone_B端权重计算(es, dir, vert_p[i], 顶点所属骨骼[i], 邻接骨骼属性.data(), 顶点到骨骼距离, k, 骨架->m_骨骼邻接);
							权重 = f_bone_A端邻接权重计算(vert, 邻接骨骼属性.data(), 顶点到骨骼距离, 当前邻接骨骼ID);
							if (权重 > 0) 顶点骨骼权重.push_back({ uint32(当前邻接骨骼ID), 权重 });
						}
						//pd = 0;
					}
					//pd = 0;
				}

				
			}


			//if (顶点所属骨骼[i].size()) {
			//	for (auto& 顶点所属骨骼ID : 顶点所属骨骼[i]) {
			//		S_骨骼属性& 骨骼属性 = 邻接骨骼属性[顶点所属骨骼ID];
			//
			//		if (骨骼属性.骨骼长度 <= 0) {
			//			continue;
			//		}
			//
			//		邻接骨骼ID[顶点所属骨骼ID]->m_父骨骼ID;
			//		邻接骨骼ID[顶点所属骨骼ID]->m_子骨骼;
			//
			//
			//		vec3 bs = _Vec3(骨骼姿态[顶点所属骨骼ID].tranformBoneA);
			//
			//		float32 骨头一半长度 = 骨骼属性.骨骼长度 * 0.5f;
			//
			//		float32 pd = f_graph_点到平面距离(vert_p[i], 骨骼属性.骨骼中间平面);
			//		float32 d = f_graph_点到直线距离(bs, 骨骼属性.骨骼方向, vert_p[i]);
			//
			//		if (d > 骨头一半长度) {
			//			float32 顶点到骨骼距离 = DEF_Min(d - 骨头一半长度, 骨头一半长度 * 2);
			//
			//			if (pd >= 0) {
			//				
			//				pd = f_bone_B端外围权重计算(vert_p[i], 顶点所属骨骼[i], 邻接骨骼属性.data(), 骨头一半长度, 顶点到骨骼距离, 顶点所属骨骼ID, pd, 骨架->m_骨骼邻接);
			//				//pd = 0;
			//			}
			//			else {
			//				//pd = f_bone_A端权重计算(vert_p[i], 顶点所属骨骼[i], 邻接骨骼属性.data(), 骨头一半长度, 顶点到骨骼距离, k);
			//				pd = 0;
			//			}
			//			//pd = 1;
			//
			//			//顶点骨骼权重.push_back({ 顶点所属骨骼ID, pd });
			//		}
			//		else {
			//			if (pd >= 0) {
			//				pd = f_bone_B端权重计算(es, dir, vert_p[i], 顶点所属骨骼[i], 邻接骨骼属性.data(), 骨头一半长度, 顶点到骨骼距离, k, 骨架->m_骨骼邻接);
			//
			//				//pd = 0;
			//			}
			//			else {
			//				pd = f_bone_A端权重计算(bs, dir, vert_p[i], 顶点所属骨骼[i], 邻接骨骼属性.data(), 骨头一半长度, 顶点到骨骼距离, k, 骨架->m_骨骼邻接);
			//
			//				//pd = 0;
			//			}
			//		}
			//		if (pd > 0) 顶点骨骼权重.push_back({ 顶点所属骨骼ID, pd });
			//
			//
			//	}
			//}
			//else {
			//	float32 minDis = 2000000000;
			//	uint32 boneID = -1;
			//
			//	for (uint32 k = 0; k < 骨节数量; ++k) {
			//		float32 d = vec_len(邻接骨骼属性[k].变换后中点 - vert_p[i]);
			//		if (d < minDis) {
			//			minDis = d;
			//			boneID = k;
			//		}
			//	}
			//
			//	if (boneID >= 0) {
			//
			//	}
			//}


			float32 权重 = 0;
			//int32 权重数量 = 0;
			for (uint32 k = 0; k < 骨节数量; ++k) {
				float32 boneLen = 骨骼姿态[k].tranformBoneA.w;

				if (boneLen <= 0) {
					continue;
				}

				S_骨骼属性& 骨骼属性 = 邻接骨骼属性[k];
				float32 骨头一半长度 = boneLen * 0.5f;

				float32 范围 = (boneLen + 骨头一半长度) * 封套范围比例;
				float32 d = vec_len(vert - 骨骼属性.变换后中点);
				//if(d < )
				if (d > 骨头一半长度 && d <= 范围) {
					范围 -= 骨头一半长度;
					d -= 骨头一半长度;
					d /= 范围;

					权重 = (1 - d) * 0.5f;
					顶点骨骼权重.push_back({ k, 权重 });
					//++权重数量;
				}
			}
			float32 最大权重 = 0;
			for (auto& e : 顶点骨骼权重) {
				最大权重 += e.weigth;
			}

			if (最大权重 > 0) {
				最大权重 = 1 / 最大权重;
				for (auto& e : 顶点骨骼权重) {
					e.weigth *= 最大权重;
				}
			}
			

			S_VertBone 顶点骨骼属性;
			顶点骨骼属性.bone_offset = 骨骼映射.size();
			顶点骨骼属性.num = 顶点骨骼权重.size();

			骨骼映射.insert(骨骼映射.end(), 顶点骨骼权重.begin(), 顶点骨骼权重.end());
			顶点骨骼[i] = 顶点骨骼属性;
			
		}
	}
	
	f_surface_fill顶点骨骼(me, 顶点骨骼);
	f_surface_fill骨骼映射(me, 骨骼映射);

}

void f_surface_计算封套权重(S_Mesh* me, const Mat44f& mat, S_物体* 物体, S_骨架* 骨架, float32 封套缩放) {
	uint32 num = me->f_get顶点数量();
	//S_骨架* 骨架 = 物体->m_骨架;
	std::vector<S_BoneMap>	骨骼映射;
	std::vector<S_VertBone>	顶点骨骼(num);

	//uint32 权重层数 = 4;
	uint32 骨头数量 = 骨架->m_骨头数量;
	if (骨头数量) {
		uint32 骨节数量 = 骨架->m_骨节数量;

		std::vector<vec3> 变换后顶点(num);
		vec3* vert_p = 变换后顶点.data();
		std::vector<vec3> 变换后法线(num);
		vec3* normal_p = 变换后法线.data();

		std::vector<std::vector<uint16>> 顶点所属骨骼(num);
		for (uint32 i = 0; i < num; ++i) {
			switch (*me->m_顶点配置Flags) {
				case E_顶点组合标志::e_坐标_法线_UV: {
					vert_p[i] = mat * f_buf_VNT_ptr(*me->m_顶点)[i].vert;
					break;
				}
				default:
					break;
			}
		}

		//for (uint32 k = 0; k < 骨架->m_骨骼邻接->count; ++k) {
		//}
		std::vector<S_封套> 封套;
		for (auto& e : 物体->m_子物体) {
			f_收集骨骼封套(封套, static_cast<S_物体*>(e));
		}
		std::vector<vec4> 平面; 平面.reserve(封套.size());
		for (auto& e : 封套) {
			平面.push_back(f_graph_坐标构建平面(e.m_端点, e.m_方向));
		}
		//for (uint32 k = 0; k < 骨节数量; ++k) {
		//	
		//}
		for (uint32 i = 0; i < num; ++i) {
			std::vector<S_BoneMap>	顶点骨骼权重;

			for (uint32 k = 0; k < 骨节数量; ++k) {
				if(封套[k].m_长度 <= 0.00000001) continue;

				float32 权重 = f_graph_点与封套相交(vert_p[i], 封套[k], 平面[k]);
				if(权重) 顶点骨骼权重.push_back({ k, 权重 });
			}


			S_VertBone 顶点骨骼属性;
			顶点骨骼属性.bone_offset = 骨骼映射.size();
			顶点骨骼属性.num = 顶点骨骼权重.size();

			骨骼映射.insert(骨骼映射.end(), 顶点骨骼权重.begin(), 顶点骨骼权重.end());
			顶点骨骼[i] = 顶点骨骼属性;
		}
	}

	f_surface_fill顶点骨骼(me, 顶点骨骼);
	f_surface_fill骨骼映射(me, 骨骼映射);
}

void f_surface_构建顶点相连面索引(S_Mesh* me, std::vector<std::vector<uint32>>& 顶点相邻面) {
	uint32 顶点数量   = me->f_get顶点数量();
	
	uint32 索引数量   = me->m_索引->m_Mem.m_数量 / 3;
	const uvec3* p索引 = (uvec3*)f_buf_UI32_ptr(*me->m_索引);

	顶点相邻面.resize(顶点数量);
	auto* 顶点相邻面指针 = 顶点相邻面.data();
//#pragma omp parallel for 
//	for (int32 i = 0; i < 顶点数量; ++i) {
//		顶点相邻面指针[i].reserve(12);
//	}

	for (uint32 面ID = 0; 面ID < 索引数量; ++面ID) {
		if (p索引[面ID].x >= 顶点数量 || p索引[面ID].y >= 顶点数量 || p索引[面ID].z >= 顶点数量) {
			std::cout<<"错误:构建顶点相邻面 取得的索引大于实际的面数量 "<< p索引[面ID].x << " " << p索引[面ID].y << " " << p索引[面ID].x << " 索引数量:" << 索引数量 << std::endl;
			continue;
		}
		顶点相邻面指针[p索引[面ID].x].emplace_back(面ID);
		顶点相邻面指针[p索引[面ID].y].emplace_back(面ID);
		顶点相邻面指针[p索引[面ID].z].emplace_back(面ID);
	}
}

void f_surface_计算三角形边相邻面索引(S_Mesh* me) {
	//std::vector<std::vector<uint32>> 顶点相邻面;
	//f_surface_构建顶点相连面索引(me, 顶点相邻面);
	
	uint32 面数量 = me->m_索引->m_Mem.m_数量 / 3;
	const uvec3* p索引 = (uvec3*)f_buf_UI32_ptr(*me->m_索引);


	std::vector<uvec3> 相邻面(面数量);
	std::vector<vec3> 面法线(面数量);
	std::vector<vec3> 面中心(面数量);
	
	std::map<uint64, uint64> 边相连面;
	for (int32 i = 0; i < 面数量; ++i) {
		uint64 keyA = uint64(p索引[i].x ^ p索引[i].y) | (uint64(p索引[i].x * p索引[i].y) << 32);
		uint64 keyB = uint64(p索引[i].y ^ p索引[i].z) | (uint64(p索引[i].y * p索引[i].z) << 32);
		uint64 keyC = uint64(p索引[i].z ^ p索引[i].x) | (uint64(p索引[i].z * p索引[i].x) << 32);



		if (边相连面.find(keyA) == 边相连面.end()) {
			边相连面[keyA] = i;
		}
		else {
			边相连面[keyA] |= uint64(i) << 32;
		}

		if (边相连面.find(keyB) == 边相连面.end()) {
			边相连面[keyB] = i;
		}
		else {
			边相连面[keyB] |= uint64(i) << 32;
		}

		if (边相连面.find(keyC) == 边相连面.end()) {
			边相连面[keyC] = i;
		}
		else {
			边相连面[keyC] |= uint64(i) << 32;
		}
	}


//#pragma omp parallel for num_threads(DEF_Min(32, 面数量+1))
	for (int32 i = 0; i < 面数量; ++i) {
		uint64 keyA = uint64(p索引[i].x ^ p索引[i].y) | (uint64(p索引[i].x * p索引[i].y) << 32);
		uint64 keyB = uint64(p索引[i].y ^ p索引[i].z) | (uint64(p索引[i].y * p索引[i].z) << 32);
		uint64 keyC = uint64(p索引[i].z ^ p索引[i].x) | (uint64(p索引[i].z * p索引[i].x) << 32);

		        
		uvec3 相邻面ID;

		uint64 边夹面A = 边相连面[keyA];
		uint64 边夹面B = 边相连面[keyB];
		uint64 边夹面C = 边相连面[keyC];

		相邻面ID.x = (边夹面A & 0x00000000ffffffff);
		相邻面ID.y = (边夹面B & 0x00000000ffffffff);
		相邻面ID.z = (边夹面C & 0x00000000ffffffff);

		if (相邻面ID.x == i) {
			相邻面ID.x = 边夹面A >> 32;
		}

		if (相邻面ID.y == i) {
			相邻面ID.y = 边夹面B >> 32;
		}

		if (相邻面ID.z == i) {
			相邻面ID.z = 边夹面C >> 32;
		}

		相邻面[i] = 相邻面ID;
	}

	f_surface_fill邻接面索引(me, 相邻面);
	//for (auto& e : 相邻面) {
	//	if (e.x >= me->m_索引->m_Mem.m_数量 || e.y >= me->m_索引->m_Mem.m_数量 || e.z >= me->m_索引->m_Mem.m_数量) {
	//		std::cout<<"\n";
	//	}
	//}

	switch (*me->m_顶点配置Flags) {
		case E_顶点组合标志::e_坐标_法线_UV: {
			S_VNT1* p顶点 = f_buf_VNT_ptr(*me->m_顶点);
	
		//#pragma omp parallel for num_threads(DEF_Min(32, 面数量+1))
			for (int32 i = 0; i < 面数量; ++i) {
				uvec3 trangle = p索引[i];
				
				面法线[i] = f_surface_FaceNormal(p顶点[trangle.x].vert, p顶点[trangle.y].vert, p顶点[trangle.z].vert);
				vec_normalize(&面法线[i]);

				面中心[i] = f_三角形中心坐标(p顶点[trangle.x].vert, p顶点[trangle.y].vert, p顶点[trangle.z].vert);
			}
			break;
		}
		default:
			break;
	}
	f_surface_fill面法线(me, 面法线);
	f_surface_fill面中心(me, 面中心);
}

void f_surface_计算面平滑法线(S_Mesh* me) {
	uint32 顶点数量 = me->m_顶点->m_Mem.m_数量;
	if(!顶点数量) return;

	std::vector<std::vector<uint32>> 顶点相邻面;
	f_surface_构建顶点相连面索引(me, 顶点相邻面);

	
	const uvec3* p索引 = (uvec3*)f_buf_UI32_ptr(*me->m_索引);
	auto* 顶点相邻面指针 = 顶点相邻面.data();

	switch (*me->m_顶点配置Flags) {
	case E_顶点组合标志::e_坐标_法线_UV: {
		S_VNT1* p顶点 = f_buf_VNT_ptr(*me->m_顶点);

//#pragma omp parallel for
#pragma omp parallel for num_threads(DEF_Min(16, 顶点数量))
		for (int32 i = 0; i < 顶点数量; ++i) {
			auto* 面索引 = 顶点相邻面指针[i].data();
			uint32 面索引数量 = 顶点相邻面指针[i].size();

			vec3 法线 = {};
//#pragma omp parallel for num_threads(4)
			for (int32 j = 0; j < 面索引数量; ++j) {
				uvec3 trangle = p索引[面索引[j]];
				法线 += f_surface_FaceNormal(p顶点[trangle.x].vert, p顶点[trangle.y].vert, p顶点[trangle.z].vert);
			}

			p顶点[i].normal = vec_normalize(法线);
		}
		break;
	}
	case E_顶点组合标志::e_坐标_法线: {
		S_VN* p顶点 = f_buf_VN_ptr(*me->m_顶点);

//#pragma omp parallel for
#pragma omp parallel for num_threads(DEF_Min(16, 顶点数量))
		for (int32 i = 0; i < 顶点数量; ++i) {
			auto* 面索引 = 顶点相邻面指针[i].data();
			uint32 面索引数量 = 顶点相邻面指针[i].size();

			vec3 法线 = {};
			for (int32 j = 0; j < 面索引数量; ++j) {
				uvec3 trangle = p索引[面索引[j]];
				法线 += f_surface_FaceNormal(p顶点[trangle.x].vert, p顶点[trangle.y].vert, p顶点[trangle.z].vert);
			}

			p顶点[i].normal = vec_normalize(法线);
		}
		break;
	}
	default:
		break;
	}

}

void f_surface_应用变换(S_Mesh* me, const Mat44f& mat) {
	uint32 顶点数量   = me->m_顶点->m_Mem.m_数量;

	switch (*(me->m_顶点配置Flags)) {
	case E_顶点组合标志::e_坐标_法线_UV: {
		S_VNT1* p顶点 = f_buf_VNT_ptr(*me->m_顶点);

		auto rotMat = f_mat44_to_33(mat);
		mat33_normalize(rotMat);

		for (int32 i = 0; i < 顶点数量; ++i) {
			p顶点[i].vert = mat * p顶点[i].vert;
			p顶点[i].normal = rotMat * p顶点[i].normal;
		}

		break;
	}
	case E_顶点组合标志::e_坐标_颜色: {
		S_VC* p顶点 = f_buf_VC_ptr(*me->m_顶点);

		for (int32 i = 0; i < 顶点数量; ++i) {
			p顶点[i].vert = mat * p顶点[i].vert;
		}
		break;
	}
	}
}

vec3 f_surface_变换包围盒(vec3 size, const Mat44f& mat) {
	vec3 v[] = { 
	    {},
		{size.x, 0, 0},
		{0, size.y, 0},
		{0, 0, size.z},

		{size.x, size.y, 0},
		{size.x, 0, size.z},
		{0, size.y, size.z},

		{size.x, size.y, size.z},
	};

	for (uint32 i = 0; i < 8; ++i) {
		v[i] = mat * v[i];
	}

	vec3 最小={1000000000,1000000000,1000000000};
	vec3 最大={-1000000000,-1000000000,-1000000000};
	for (uint32 i = 0; i < 8; ++i) {
		最小 = vec_Min(v[i], 最小);
		最大 = vec_Max(v[i], 最大);
	}

	return 最大 - 最小;
}


float32 f_bone_B端权重计算(const vec3& 端坐标
						, const vec3& 方向
						, const vec3& 顶点
						, const std::vector<uint16>& 顶点所属骨骼
						, const S_骨骼属性* 骨骼属性
						//, const float32* 骨骼长度
						//, float32 骨头一半长度
						, float32 顶点到骨骼距离
						, int32 当前骨骼ID
						, S_骨骼邻接数组* 邻接骨骼
						) {
	vec4 B端平面 = f_graph_坐标构建平面(端坐标, 方向);
	float32 pd = 1;

	float32 B端距离 = f_graph_点到平面距离(顶点, B端平面);


	
	if (B端距离 > 0) {
		//float32 mixd = 1000000000;
		//int32 最近骨骼ID = -1;
		//f_bone_当前顶点最短骨骼(mixd, 最近骨骼ID, 顶点所属骨骼, 骨骼属性, 当前骨骼ID);

		float32 邻接骨骼距离 = f_graph_点到平面距离(顶点, 骨骼属性[当前骨骼ID].A端平面);

		//mixd *= 0.5f;
		pd = (顶点到骨骼距离 - DEF_Min(fabs(邻接骨骼距离), 顶点到骨骼距离)) / 顶点到骨骼距离;
		pd *= 0.5f;

		//if (最近骨骼ID >= 0) {
		//	int32 父骨骼ID = 邻接骨骼->ptr_userData[当前骨骼ID]->m_子骨骼->count;
		//	if (父骨骼ID <= 0) {
		//		//return 1;
		//	}
		//	//pd = 0;
		//}
		//else {
		//	pd = 0;
		//}
		//pd = 0;
	}
	else {
		//int32 父骨骼ID = 邻接骨骼->ptr_userData[当前骨骼ID]->m_子骨骼->count;
		//if (父骨骼ID <= 0) {
		//	//return 1;
		//}
		
		pd = DEF_Min(fabs(B端距离), 顶点到骨骼距离) / 顶点到骨骼距离;
		pd = (pd + 1) * 0.5f;
		//pd = 0;
	}
	
	return pd;
}

float32 f_bone_A端权重计算(const vec3& 端坐标
							, const vec3& 方向
							, const vec3& 顶点
							, const std::vector<uint16>& 顶点所属骨骼
							, const S_骨骼属性* 骨骼属性
							//, const float32* 骨骼长度
							//, float32 骨头一半长度
							, float32 顶点到骨骼距离
							, int32 当前骨骼ID
							, S_骨骼邻接数组* 邻接骨骼
							) {

	vec4 A端平面 = f_graph_坐标构建平面(端坐标, 方向);
	float32 pd = 0;


	//float32 mixd = 1000000000;
	//int32 最近骨骼ID = -1;
	//f_bone_当前顶点最短骨骼(mixd, 最近骨骼ID, 顶点所属骨骼, 骨骼属性, 当前骨骼ID);



	float32 A端距离 = f_graph_点到平面距离(顶点, A端平面);
	if (A端距离 >= 0) {
		
		//int32 父骨骼ID = 邻接骨骼->ptr_userData[当前骨骼ID]->m_父骨骼ID;
		//if (父骨骼ID <= 0 || 骨骼属性[父骨骼ID].骨骼长度 <= 0) {
		//	//return 0;
		//}
		

		pd = DEF_Min(fabs(A端距离), 顶点到骨骼距离) / 顶点到骨骼距离;
		pd = (pd + 1) * 0.5f;
		//pd = 0;
	}
	else {

		float32 邻接骨骼距离 = f_graph_点到平面距离(顶点, 骨骼属性[当前骨骼ID].B端平面);

		邻接骨骼距离 = DEF_Min(fabs(邻接骨骼距离), 顶点到骨骼距离);
		pd = (顶点到骨骼距离 - 邻接骨骼距离) / 顶点到骨骼距离;
		pd *= 0.5f;

		//if (最近骨骼ID >= 0) {
		//	int32 父骨骼ID = 邻接骨骼->ptr_userData[当前骨骼ID]->m_父骨骼ID;
		//	if (父骨骼ID <= 0 || 骨骼属性[父骨骼ID].骨骼长度 <= 0) {
		//		//return 0;
		//	}
		//	//pd = 0;
		//}
		//else {
		//	//pd = (骨头一半长度 - DEF_Min(fabs(A端距离), 骨头一半长度)) / 骨头一半长度 * 0.5;
		//	pd = 0;
		//}
		//pd = 0;
	}
	//pd = 0;
	return pd;
}


float32 f_bone_A端邻接权重计算(const vec3& 顶点, const S_骨骼属性* 骨骼属性, float32 顶点到骨骼距离, int32 当前骨骼ID) {
	float32 B端距离 = f_graph_点到平面距离(顶点, 骨骼属性[当前骨骼ID].B端平面);
	float32 pd = 0;
	if (B端距离 >= 0) {
		B端距离 = DEF_Min(fabs(B端距离), 顶点到骨骼距离);
		pd = (顶点到骨骼距离 - B端距离) / 顶点到骨骼距离;
		pd *= 0.5f;
	}

	return pd;
}

float32 f_bone_B端邻接权重计算(const vec3& 顶点, const S_骨骼属性* 骨骼属性, float32 顶点到骨骼距离, int32 当前骨骼ID) {
	float32 A端距离 = f_graph_点到平面距离(顶点, 骨骼属性[当前骨骼ID].A端平面);
	float32 pd = 0;
	if (A端距离 <= 0) {
		A端距离 = DEF_Min(fabs(A端距离), 顶点到骨骼距离);
		pd = (顶点到骨骼距离 - A端距离) / 顶点到骨骼距离;
		pd *= 0.5f;
	}

	return pd;
}


float32 f_bone_外围权重计算(
						const vec3& 顶点
						, const std::vector<uint16>& 顶点所属骨骼
						, const S_骨骼属性* 骨骼属性
						//, const float32* 骨骼长度
						, float32 骨头一半长度
						, float32 顶点到骨骼距离
						, int32 当前骨骼ID
						, S_骨骼邻接数组* 邻接骨骼
						, float32 pd
) {
	
	//float32 B端距离 = f_graph_点到平面距离(顶点, 骨骼属性[当前骨骼ID].B端平面);
	//float32 pd = 0;
	float32 顶点到骨骼距离比 = 顶点到骨骼距离 / (骨头一半长度 * 2);

	if (pd >= 0) {
		//B端距离 = DEF_Min(骨头一半长度, fabs(B端距离)) / 骨头一半长度;
		pd = (骨头一半长度 - pd) / 骨头一半长度;
	}
	else {
		pd = (骨头一半长度 - fabs(pd)) / 骨头一半长度;
	}

	pd = 0.5 + (0.5 - (顶点到骨骼距离比 * 0.5f)) * pd;
	
	return pd;
}


float32 f_bone_外围邻接权重计算(
						const vec3& 顶点
						, float32 pd
						, float32 骨头长度
						, float32 顶点到骨骼距离
) {
	float32 顶点到骨骼距离比 = 顶点到骨骼距离 / 骨头长度;

	pd = fabs(pd);
	pd = (DEF_Min(pd, 骨头长度)) / 骨头长度;

	//pd = (0.5 - (顶点到骨骼距离比 * 0.5f)) * pd;
	//pd = 0.5 + (0.5 - (顶点到骨骼距离比 * 0.5f)) * pd;
	pd = 0.5 * pd;
	return pd;
}




void f_bone_当前顶点最短骨骼(float32& 最小距离
					, int32& 最近骨骼ID
					, const std::vector<uint16>& 顶点所属骨骼
					, const S_骨骼属性* 骨骼属性
					, int32 当前骨骼ID
					) {
	for (auto 顶点所属骨骼ID : 顶点所属骨骼) {
		if (顶点所属骨骼ID != 当前骨骼ID) {
			float32 骨骼长度 = 骨骼属性[顶点所属骨骼ID].骨骼长度;

			if (骨骼长度 < 最小距离 && 骨骼长度 > 0) {
				最小距离 = 骨骼长度;
				最近骨骼ID = 顶点所属骨骼ID;
			}
		}
	}
}

void f_bone_最短骨骼(float32& 最小距离, int32& 最近骨骼ID, const S_骨骼属性* 骨骼属性, const S_I32Array* 邻接骨骼) {
	for (uint32 i = 0; i < 邻接骨骼->count; ++i) {
		if (骨骼属性[邻接骨骼->ptr_userData[i]].骨骼长度 < 最小距离) {
			最小距离 = 骨骼属性[邻接骨骼->ptr_userData[i]].骨骼长度;
			最近骨骼ID = 邻接骨骼->ptr_userData[i];
		}
	}
}

















				//vec3 be = boneMat[k] * vec3{0, 0, boneLen[k]};
				//vec4 q = f_graph_quat两向量(normalize(bs), DEF_骨骼朝向);
				//vec3 dir = vec_normalize(be - bs);
				//vec3 dir = f_graph_quatTranformInv(f_graph_quat反向(骨骼姿态[k].quat), DEF_骨骼朝向);
				//vec3 dir = f_graph_quatTranformInv(q, DEF_骨骼朝向);

				//vec3 dir = f_graph_quatTranformInv(f_graph_quat反向(q), DEF_骨骼朝向);
				//vec3 dir = f_graph_quat变换坐标(f_graph_quat反向(骨骼姿态[k].quat), DEF_骨骼朝向);

//minDir *= 0.1;
			//uint8 最小层 = 0;
			//float32 temp最小权重 = -1;
			//for (uint32 j = 0; j < 权重层数; ++j) {
			//	uint32 offset = j * num + i;
			//	if (temp最小权重 > 权重[offset]) {
			//		temp最小权重 = 权重[offset];
			//		最小层 = j;
			//	}
			//}
			//
			//权重[最小层 * num + i] = minDir;
			//


		//for (uint32 i = 0; i < num; ++i) {
		//	for (uint32 k = 0; k < 骨头数量; ++k) {
		//		vec3 bs = boneMat[k] * vec3{};
		//		vec3 be = boneMat[k] * vec3{ 0, 0, boneLen[k] };
		//		vec3 dir = vec_normalize(be - bs);
		//
		//
		//		vec3 点到骨骼朝向 = f_graph_计算点到直线垂足坐标(bs, dir, vert_p[i]);
		//		点到骨骼朝向 = vec_normalize(点到骨骼朝向 - vert_p[i]);
		//		float32 顶点法线垂直骨骼强度 = vec_dot(点到骨骼朝向, normal_p[i]);
		//
		//	}
		//}


				//float32 大圈权重 = 0;
				//if (封套大小 >= 0) {
				//	
				//}
				//else {
				//	大圈权重 = (DEF_Min(距中心点距离, boneLen) - 骨头一半长度) / 骨头一半长度;
				//	//大圈权重 = 1.0 - 大圈权重 / 骨头一半长度;
				//}
				//auto 平面 = PlaneFromPoints({ 0,-0.1f,-0.1f }, { 0,1,0 }, { 0,0,1 });
				//f_graph_plane()




//for (auto 邻接骨骼ID : 顶点所属骨骼) {
		//	if (邻接骨骼ID != 最近骨骼ID) {
		//		if (骨骼长度[骨骼ID] < mixd) {
		//			mixd = 骨骼长度[骨骼ID];
		//			最近骨骼ID = 骨骼ID;
		//		}
		//	}
		//}






